use crate::lexing::TokenType;

use std::fmt::Debug;

enum Expr {
    // todo, 有必要在这里保留行的信息么
    Unary(TokenType, Box<Expr>),
    Grouping(Box<Expr>),
    Str(String),
    Number(f64),
    Bool(bool),
    Binary(Box<Expr>, TokenType, Box<Expr>),
}

use Expr::*;

impl Debug for Expr {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Unary(t, e) => write!(f, "({:?} {:?})", t, e),
            Grouping(e) => write!(f, "(group {:?})", e),
            Str(s) => write!(f, "{}", s),
            Number(n) => write!(f, "{}", n),
            Bool(b) => write!(f, "{}", b),
            Binary(l, op, r) => write!(f, "({:?}, {:?}, {:?})", op, l, r),
        }
    }
}

#[cfg(test)]
mod test {

    use super::*;

    #[test]
    fn test_print() {
        let expr = Binary(
            Box::new(Binary(
                Box::new(Number(10.0)),
                TokenType::Plus,
                Box::new(Number(20.0)),
            )),
            TokenType::Minus,
            Box::new(Grouping(Box::new(Unary(
                TokenType::Bang,
                Box::new(Number(12.0)),
            )))),
        );

        println!("{:?}", expr);
    }
}
